using System;
using System.IO;

namespace CLELCore
{
	public class CLELFileReader : ICLELReader,IDisposable
	{
		//path to file that is being read
		private String _path;
		//buffer of bytes from file
		private byte [] _buffer;
		private FileStream _reader;
		//if reader has been disposed or closed, stop user from reading
		private bool _disposed;
		private bool _little_endian;

		public String Path
		{
			get
			{
				return _path;
			}
		}

		public int EOF
		{
			get
			{
				return -1;
			}
		}

		public bool IsLittleEndian
		{
			get
			{
				return _little_endian;
			}
			set
			{
				_little_endian = value;
			}
		}

		public CLELFileReader(String path)
		{
			_path = path;
			_reader = new FileStream(path,FileMode.Open,FileAccess.Read);
			_disposed = false;
			_buffer = new byte[8];
			_little_endian = true;
		}

		public int ReadByte(ref byte val)
		{
			if(_disposed)
				return EOF;
			int ret = _reader.ReadByte();
			if(ret == EOF)
				return EOF;
			val = (byte)ret;
			return 1;
		}

		public int ReadShort(ref short val)
		{
			if(_disposed)
				return EOF;
			int ret = _reader.Read(_buffer,0,2);
			if(ret < 2)
				return EOF;
			if(_little_endian)
				val = Endiness.ShortLittleToBigEndian(_buffer[0],_buffer[1]);
			else
				val = Endiness.ShortBigToLittleEndian(_buffer[0],_buffer[1]);
				
			return 2;
		}

		public int ReadInt(ref int val)
		{
			if(_disposed)
				return EOF;
			int ret = _reader.Read(_buffer,0,4);
			if(ret < 4)
				return EOF;
			if(_little_endian)
				val = Endiness.IntLittleToBigEndian(_buffer[0],_buffer[1],
					_buffer[2],_buffer[3]);
			else
				val = Endiness.IntBigToLittleEndian(_buffer[0],_buffer[1],
					_buffer[2],_buffer[3]);

			return 4;
		}

		public uint ReadUnsignedInt(ref uint val)
		{
			if(_disposed)
				return (uint)EOF;
			int ret = _reader.Read(_buffer,0,4);
			if(ret < 4)
				return (uint)EOF;
			if(_little_endian)
				val = Endiness.UnsignedIntLittleToBigEndian(_buffer[0],_buffer[1],
					_buffer[2],_buffer[3]);
			else
				val = Endiness.UnsignedIntBigToLittleEndian(_buffer[0],_buffer[1],
					_buffer[2],_buffer[3]);

			return 4;
		}

		public int ReadLong(ref long val)
		{
			if(_disposed)
				return EOF;
			int ret = _reader.Read(_buffer,0,8);
			if(ret < 8)
				return EOF;
			if(_little_endian)
				val = Endiness.LongLittleToBigEndian(_buffer[0],_buffer[1],
					_buffer[2],_buffer[3],_buffer[4],_buffer[5],
					_buffer[6],_buffer[7]);
			else
				val = Endiness.LongBigToLittleEndian(_buffer[0],_buffer[1],
					_buffer[2],_buffer[3],_buffer[4],_buffer[5],
					_buffer[6],_buffer[7]);
			
			return 8;
		}

		public int Read(byte [] buffer,int offset,int length)
		{
			if(_disposed)
				return EOF;
			int ret = _reader.Read(buffer,offset,length);
			if(ret != length)
				return EOF;
			return ret;
		}

		public void Close()
		{
			Dispose();
		}

		//make sure that FileStream was disposed
		public void Dispose()
		{
			_reader.Dispose();
			_disposed = true;
		}
	}
}
